package com.rw.coco.handler.message.reply.handler.command.sender;

import com.rw.coco.api.data.model.CharacterModel;
import com.rw.coco.api.data.model.CharacterPropertyModel;
import com.rw.coco.handler.message.event.CocoMessageEvent;
import com.rw.coco.handler.message.reply.handler.command.assistant.PropReader;
import com.rw.coco.handler.message.reply.handler.command.bean.CocoProp;
import com.rw.coco.handler.message.reply.handler.command.exception.global.NumberOverflowException;
import com.rw.coco.service.CharacterPropertyService;
import com.rw.coco.service.CharacterService;
import com.rw.tool.util.string.StringUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

public class STSender extends BaseSender {
    // 连携属性的名称
    // 血量-连携血量上限
    private final String hp = anotherNameConfig.getMainName("hp");
    private final String maxHp = anotherNameConfig.getMainName("maxHp");
    // 魔法-连携魔法上限
    private final String mp = anotherNameConfig.getMainName("mp");
    private final String maxMp = anotherNameConfig.getMainName("maxMp");

    public STSender(CocoMessageEvent event) {
        super(event);
    }

    /**
     * 将 "属性名[属性值]属性名[属性值]" 格式的字符串解析为属性列表
     * 如果解析失败，则会返回 false
     * 解析失败时，会自动回复错误信息
     *
     * @return 解析是否成功
     */
    public Optional<List<CocoProp>> getCocoProp(String message) {
        // 属性读取器
        PropReader propReader = new PropReader(message, anotherNameConfig);
        // 读取属性
        List<CocoProp> cocoPropList = new ArrayList<>();
        while (propReader.hasNext()) {
            CocoProp cocoProp = propReader.next();
            cocoPropList.add(cocoProp);

            // 连携设定，如果设置血量/魔法，应当同时设置血量上限
            Optional<CocoProp> extraProp = incidentally(cocoProp);
            extraProp.ifPresent(cocoPropList::add);
        }

        // 如果读取未完成
        if (!propReader.done()) {
            String errorPosition = propReader.getErrorPosition();
            event.sendBack(diceReply.setPropError(event, errorPosition));
            return Optional.empty();
        }

        return Optional.of(cocoPropList);
    }

    /**
     * 连携设置属性
     * 如果设置血量，应当同时设置血量上限，同理还有魔法上限，理智上限等
     * 这个方法可以判断属性是否是连携设置的属性，如果是，则返回被连携的属性
     *
     * @param cocoProp 设置的属性
     */
    private Optional<CocoProp> incidentally(CocoProp cocoProp) {
        // 使用propService判断用户是否拥有这个属性
        CharacterPropertyService propService = new CharacterPropertyService(mapper);

        // 如果有这个属性，并且没有设置过，则连携设定
        if (hp.equals(cocoProp.getName()) && !propService.contains(accountModel, hp)) {
            // 如果是血量，则设置血量上限
            CocoProp prop = new CocoProp(maxHp, cocoProp.getValue(), anotherNameConfig);
            return Optional.of(prop);
        } else if (mp.equals(cocoProp.getName()) && !propService.contains(accountModel, mp)) {
            // 如果是魔法，则设置魔法上限
            CocoProp prop = new CocoProp(maxMp, cocoProp.getValue(), anotherNameConfig);
            return Optional.of(prop);
        }

        return Optional.empty();
    }

    /**
     * 经过解析并且成功之后，调用此方法，将属性入库
     */
    public void save(List<CocoProp> cocoPropList) {
        // 判断设置的属性是否超过限制
        for (CocoProp cocoProp : cocoPropList) {
            // 如果超过限制
            if (cocoProp.getValue() < CocoProp.MIN_VALUE || cocoProp.getValue() > CocoProp.MAX_VALUE) {
                event.sendBack(diceReply.setPropOutOfRange(event, cocoProp, CocoProp.MIN_VALUE, CocoProp.MAX_VALUE));
                return;
            }
        }

        // 查询出用户的角色
        CharacterService characterService = new CharacterService(mapper);
        CharacterModel character = characterService.getOrDefault(accountModel);

        // 转化属性
        Set<CharacterPropertyModel> propertyModelSet = cocoPropList.stream()
                .map(prop -> new CharacterPropertyModel(character.getCharacterId(), prop.getName(), prop.getValue()))
                .collect(Collectors.toSet());

        // 插入
        characterPropertyMapper.setProperties(propertyModelSet);

        event.sendBack(diceReply.setPropSuccess(event));
    }

    /**
     * 解析属性，如果解析成功，则入库
     */
    public void parseAndSaveCocoProp(String message) {
        try {
            Optional<List<CocoProp>> optional = getCocoProp(message);
            optional.ifPresent(this::save);
        } catch (NumberOverflowException exception) {
            event.sendBack(diceReply.numberOverflowException(event));
        }
    }

    /**
     * 清除用户的所有属性
     */
    public void clearProp() {
        characterPropertyMapper.deleteAllProperties(accountModel.getCharacterId());
        event.sendBack(diceReply.clearAllProp(event));
    }

    /**
     * 删除用户的某个属性
     *
     * @param propName 属性名
     */
    public void deleteProp(String propName) {
        Integer characterId = accountModel.getCharacterId();

        // 获得所有的属性，以及目标属性
        Set<CharacterPropertyModel> properties = characterPropertyMapper.getProperties(characterId);
        CharacterPropertyModel target = CharacterPropertyModel.of(characterId, propName);

        // 如果存在这个属性，则删除
        if (properties.contains(target)) {
            characterPropertyMapper.deleteProperties(characterId, propName);
            event.sendBack(diceReply.delete(event, propName));
        } else {
            // 如果不存在，则返回未找到
            event.sendBack(diceReply.deleteButNotFound(event, propName));
        }
    }

    /**
     * 展示用户的某个属性
     * 如果传入的属性名为空，则展示所有属性
     *
     * @param propName 属性名
     */
    public void show(String propName) {
        if (StringUtil.isBlank(propName)) {
            showAllProp();
        } else {
            showOneProp(anotherNameConfig.getMainName(propName));
        }
    }

    /**
     * 展示一个属性的属性值
     *
     * @param propName 属性名
     */
    private void showOneProp(String propName) {
        // 查找角色对应的属性
        CharacterPropertyService propService = new CharacterPropertyService(mapper);
        Optional<CharacterPropertyModel> modelOptional = propService.getProp(accountModel.getCharacterId(), propName);

        // 如果没有找到对应的属性，则直接返回未找到
        if (!modelOptional.isPresent()) {
            event.sendBack(diceReply.setShowNotFindProp(event, propName));
            return;
        }

        // 展示属性
        CharacterPropertyModel model = modelOptional.get();
        event.sendBack(diceReply.setShowOne(event, model));
    }

    /**
     * 展示所有属性的属性值
     */
    private void showAllProp() {
        // 查出角色所有的属性
        Set<CharacterPropertyModel> properties = characterPropertyMapper.getProperties(accountModel.getCharacterId());

        // 展示属性
        event.sendBack(diceReply.setShowAll(event, properties));
    }
}
